home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / groff108.lha / groff-1.08 / pic / lex.cc < prev    next >
C/C++ Source or Header  |  1993-03-30  |  40KB  |  1,939 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include "pic.h"
  22. #include "ptable.h"
  23. #include "object.h"
  24. #include "pic.tab.h"
  25.  
  26. declare_ptable(char)
  27. implement_ptable(char)
  28.  
  29. PTABLE(char) macro_table;
  30.  
  31. class macro_input : public input {
  32.   char *s;
  33.   char *p;
  34. public:
  35.   macro_input(const char *);
  36.   ~macro_input();
  37.   int get();
  38.   int peek();
  39. };
  40.  
  41. class argument_macro_input : public input {
  42.   char *s;
  43.   char *p;
  44.   char *ap;
  45.   int argc;
  46.   char *argv[9];
  47. public:
  48.   argument_macro_input(const char *, int, char **);
  49.   ~argument_macro_input();
  50.   int get();
  51.   int peek();
  52. };
  53.  
  54. input::input() : next(0)
  55. {
  56. }
  57.  
  58. input::~input()
  59. {
  60. }
  61.  
  62. int input::get_location(const char **, int *)
  63. {
  64.   return 0;
  65. }
  66.  
  67. file_input::file_input(FILE *f, const char *fn)
  68. : lineno(0), ptr(""), filename(fn)
  69. {
  70.   fp = f;
  71. }
  72.  
  73. file_input::~file_input()
  74. {
  75.   fclose(fp);
  76. }
  77.  
  78. int file_input::read_line()
  79. {
  80.   for (;;) {
  81.     line.clear();
  82.     lineno++;
  83.     for (;;) {
  84.       int c = getc(fp);
  85.       if (c == EOF)
  86.     break;
  87.       else if (illegal_input_char(c))
  88.     lex_error("illegal input character code %1", c);
  89.       else {
  90.     line += char(c);
  91.     if (c == '\n') 
  92.       break;
  93.       }
  94.     }
  95.     if (line.length() == 0)
  96.       return 0;
  97.     if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
  98.       && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
  99.       && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
  100.           || compatible_flag))) {
  101.       line += '\0';
  102.       ptr = line.contents();
  103.       return 1;
  104.     }
  105.   }
  106. }
  107.  
  108. int file_input::get()
  109. {
  110.   if (*ptr != '\0' || read_line())
  111.     return (unsigned char)*ptr++;
  112.   else
  113.     return EOF;
  114. }
  115.  
  116. int file_input::peek()
  117. {
  118.   if (*ptr != '\0' || read_line())
  119.     return (unsigned char)*ptr;
  120.   else
  121.     return EOF;
  122. }
  123.  
  124. int file_input::get_location(const char **fnp, int *lnp)
  125. {
  126.   *fnp = filename;
  127.   *lnp = lineno;
  128.   return 1;
  129. }
  130.  
  131. macro_input::macro_input(const char *str)
  132. {
  133.   p = s = strsave(str);
  134. }
  135.  
  136. macro_input::~macro_input()
  137. {
  138.   a_delete s;
  139. }
  140.  
  141. int macro_input::get()
  142. {
  143.   if (p == 0 || *p == '\0')
  144.     return EOF;
  145.   else
  146.     return (unsigned char)*p++;
  147. }
  148.  
  149. int macro_input::peek()
  150. {
  151.   if (p == 0 || *p == '\0')
  152.     return EOF;
  153.   else
  154.     return (unsigned char)*p;
  155. }
  156.  
  157. // Character respresenting $1.  Must be illegal input character.
  158. #define ARG1 14
  159.  
  160. char *process_body(const char *body)
  161. {
  162.   char *s = strsave(body);
  163.   int j = 0;
  164.   for (int i = 0; s[i] != '\0'; i++)
  165.     if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
  166.       if (s[i+1] != '0')
  167.     s[j++] = ARG1 + s[++i] - '1';
  168.     }
  169.     else
  170.       s[j++] = s[i];
  171.   s[j] = '\0';
  172.   return s;
  173. }
  174.  
  175.  
  176. argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
  177. : argc(ac), ap(0)
  178. {
  179.   for (int i = 0; i < argc; i++)
  180.     argv[i] = av[i];
  181.   p = s = process_body(body);
  182. }
  183.  
  184.  
  185. argument_macro_input::~argument_macro_input()
  186. {
  187.   for (int i = 0; i < argc; i++)
  188.     a_delete argv[i];
  189.   a_delete s;
  190. }
  191.  
  192. int argument_macro_input::get()
  193. {
  194.   if (ap) {
  195.     if (*ap != '\0')
  196.       return (unsigned char)*ap++;
  197.     ap = 0;
  198.   }
  199.   if (p == 0)
  200.     return EOF;
  201.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  202.     int i = *p++ - ARG1;
  203.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  204.       ap = argv[i];
  205.       return (unsigned char)*ap++;
  206.     }
  207.   }
  208.   if (*p == '\0')
  209.     return EOF;
  210.   return (unsigned char)*p++;
  211. }
  212.  
  213. int argument_macro_input::peek()
  214. {
  215.   if (ap) {
  216.     if (*ap != '\0')
  217.       return (unsigned char)*ap;
  218.     ap = 0;
  219.   }
  220.   if (p == 0)
  221.     return EOF;
  222.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  223.     int i = *p++ - ARG1;
  224.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  225.       ap = argv[i];
  226.       return (unsigned char)*ap;
  227.     }
  228.   }
  229.   if (*p == '\0')
  230.     return EOF;
  231.   return (unsigned char)*p;
  232. }
  233.  
  234. class input_stack {
  235.   static input *current_input;
  236.   static int bol_flag;
  237. public:
  238.   static void push(input *);
  239.   static void clear();
  240.   static int get_char();
  241.   static int peek_char();
  242.   static int get_location(const char **fnp, int *lnp);
  243.   static void push_back(unsigned char c, int was_bol = 0);
  244.   static int bol();
  245. };
  246.  
  247. input *input_stack::current_input = 0;
  248. int input_stack::bol_flag = 0;
  249.  
  250. inline int input_stack::bol()
  251. {
  252.   return bol_flag;
  253. }
  254.  
  255. void input_stack::clear()
  256. {
  257.   while (current_input != 0) {
  258.     input *tem = current_input;
  259.     current_input = current_input->next;
  260.     delete tem;
  261.   }
  262.   bol_flag = 1;
  263. }
  264.  
  265. void input_stack::push(input *in)
  266. {
  267.   in->next = current_input;
  268.   current_input = in;
  269. }
  270.  
  271. void lex_init(input *top)
  272. {
  273.   input_stack::clear();
  274.   input_stack::push(top);
  275. }
  276.  
  277. void lex_cleanup()
  278. {
  279.   while (input_stack::get_char() != EOF)
  280.     ;
  281. }
  282.  
  283. int input_stack::get_char()
  284. {
  285.   while (current_input != 0) {
  286.     int c = current_input->get();
  287.     if (c != EOF) {
  288.       bol_flag = c == '\n';
  289.       return c;
  290.     }
  291.     // don't pop the top-level input off the stack
  292.     if (current_input->next == 0)
  293.       return EOF;
  294.     input *tem = current_input;
  295.     current_input = current_input->next;
  296.     delete tem;
  297.   }
  298.   return EOF;
  299. }
  300.  
  301. int input_stack::peek_char()
  302. {
  303.   while (current_input != 0) {
  304.     int c = current_input->peek();
  305.     if (c != EOF)
  306.       return c;
  307.     if (current_input->next == 0)
  308.       return EOF;
  309.     input *tem = current_input;
  310.     current_input = current_input->next;
  311.     delete tem;
  312.   }
  313.   return EOF;
  314. }
  315.  
  316. class char_input : public input {
  317.   int c;
  318. public:
  319.   char_input(int);
  320.   int get();
  321.   int peek();
  322. };
  323.  
  324. char_input::char_input(int n) : c((unsigned char)n)
  325. {
  326. }
  327.  
  328. int char_input::get()
  329. {
  330.   int n = c;
  331.   c = EOF;
  332.   return n;
  333. }
  334.  
  335. int char_input::peek()
  336. {
  337.   return c;
  338. }
  339.  
  340. void input_stack::push_back(unsigned char c, int was_bol)
  341. {
  342.   push(new char_input(c));
  343.   bol_flag = was_bol;
  344. }
  345.  
  346. int input_stack::get_location(const char **fnp, int *lnp)
  347. {
  348.   for (input *p = current_input; p; p = p->next)
  349.     if (p->get_location(fnp, lnp))
  350.       return 1;
  351.   return 0;
  352. }
  353.  
  354. string context_buffer;
  355.  
  356. string token_buffer;
  357. double token_double;
  358. int token_int;
  359.  
  360. void interpolate_macro_with_args(const char *body)
  361. {
  362.   char *argv[9];
  363.   int argc = 0;
  364.   for (int i = 0; i < 9; i++)
  365.     argv[i] = 0;
  366.   int level = 0;
  367.   int c;
  368.   enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL;
  369.   do {
  370.     token_buffer.clear();
  371.     for (;;) {
  372.       c = input_stack::get_char();
  373.       if (c == EOF) {
  374.     lex_error("end of input while scanning macro arguments");
  375.     break;
  376.       }
  377.       if (state == NORMAL && level == 0 && (c == ',' || c == ')')) {
  378.     if (token_buffer.length() > 0) {
  379.       token_buffer +=  '\0';
  380.       argv[argc] = strsave(token_buffer.contents());
  381.     }
  382.     // for `foo()', argc = 0
  383.     if (argc > 0 || c != ')' || i > 0)
  384.       argc++;
  385.     break;
  386.       }
  387.       token_buffer += char(c);
  388.       switch (state) {
  389.       case NORMAL:
  390.     if (c == '"')
  391.       state = IN_STRING;
  392.     else if (c == '(')
  393.       level++;
  394.     else if (c == ')')
  395.       level--;
  396.     break;
  397.       case IN_STRING:
  398.     if (c == '"')
  399.       state = NORMAL;
  400.     else if (c == '\\')
  401.       state = IN_STRING_QUOTED;
  402.     break;
  403.       case IN_STRING_QUOTED:
  404.     state = IN_STRING;
  405.     break;
  406.       }
  407.     }
  408.   } while (c != ')' && c != EOF);
  409.   input_stack::push(new argument_macro_input(body, argc, argv));
  410. }
  411.  
  412. static int docmp(const char *s1, int n1, const char *s2, int n2)
  413. {
  414.   if (n1 < n2) {
  415.     int r = memcmp(s1, s2, n1);
  416.     return r ? r : -1;
  417.   }
  418.   else if (n1 > n2) {
  419.     int r = memcmp(s1, s2, n2);
  420.     return r ? r : 1;
  421.   }
  422.   else
  423.     return memcmp(s1, s2, n1);
  424. }
  425.  
  426. int lookup_keyword(const char *str, int len)
  427. {
  428.   static struct keyword {
  429.     const char *name;
  430.     int token;
  431.   } table[] = {
  432.     "Here", HERE,
  433.     "above", ABOVE,
  434.     "aligned", ALIGNED,
  435.     "and", AND,
  436.     "arc", ARC,
  437.     "arrow", ARROW,
  438.     "at", AT,
  439.     "atan2", ATAN2,
  440.     "below", BELOW,
  441.     "between", BETWEEN,
  442.     "bottom", BOTTOM,
  443.     "box", BOX,
  444.     "by", BY,
  445.     "ccw", CCW,
  446.     "center", CENTER,
  447.     "chop", CHOP,
  448.     "circle", CIRCLE,
  449.     "command", COMMAND,
  450.     "copy", COPY,
  451.     "cos", COS,
  452.     "cw", CW,
  453.     "dashed", DASHED,
  454.     "define", DEFINE,
  455.     "diam", DIAMETER,
  456.     "diameter", DIAMETER,
  457.     "do", DO,
  458.     "dotted", DOTTED,
  459.     "down", DOWN,
  460.     "ellipse", ELLIPSE,
  461.     "else", ELSE,
  462.     "end", END,
  463.     "exp", EXP,
  464.     "fill", FILL,
  465.     "filled", FILL,
  466.     "for", FOR,
  467.     "from", FROM,
  468.     "height", HEIGHT,
  469.     "ht", HEIGHT,
  470.     "if", IF,
  471.     "int", INT,
  472.     "invis", INVISIBLE,
  473.     "invisible", INVISIBLE,
  474.     "last", LAST,
  475.     "left", LEFT,
  476.     "line", LINE,
  477.     "ljust", LJUST,
  478.     "log", LOG,
  479.     "lower", LOWER,
  480.     "max", K_MAX,
  481.     "min", K_MIN,
  482.     "move", MOVE,
  483.     "of", OF,
  484.     "plot", PLOT,
  485.     "print", PRINT,
  486.     "rad", RADIUS,
  487.     "radius", RADIUS,
  488.     "rand", RAND,
  489.     "reset", RESET,
  490.     "right", RIGHT,
  491.     "rjust", RJUST,
  492.     "same", SAME,
  493.     "sh", SH,
  494.     "sin", SIN,
  495.     "spline", SPLINE,
  496.     "sprintf", SPRINTF,
  497.     "sqrt", SQRT,
  498.     "start", START,
  499.     "the", THE,
  500.     "then", THEN,
  501.     "thick", THICKNESS,
  502.     "thickness", THICKNESS,
  503.     "thru", THRU,
  504.     "to", TO,
  505.     "top", TOP,
  506.     "undef", UNDEF,
  507.     "until", UNTIL,
  508.     "up", UP,
  509.     "upper", UPPER,
  510.     "way", WAY,
  511.     "wid", WIDTH,
  512.     "width", WIDTH,
  513.     "with", WITH,
  514.   };
  515.   
  516.   const keyword *start = table;
  517.   const keyword *end = table + sizeof(table)/sizeof(table[0]);
  518.   while (start < end) {
  519.     // start <= target < end
  520.     const keyword *mid = start + (end - start)/2;
  521.     
  522.     int cmp = docmp(str, len, mid->name, strlen(mid->name));
  523.     if (cmp == 0)
  524.       return mid->token;
  525.     if (cmp < 0)
  526.       end = mid;
  527.     else
  528.       start = mid + 1;
  529.   }
  530.   return 0;
  531. }
  532.  
  533. int get_token_after_dot(int c)
  534. {
  535.   // get_token deals with the case where c is a digit
  536.   switch (c) {
  537.   case 'h':
  538.     input_stack::get_char();
  539.     c = input_stack::peek_char();
  540.     if (c == 't') {
  541.       input_stack::get_char();
  542.       context_buffer = ".ht";
  543.       return DOT_HT;
  544.     }
  545.     else if (c == 'e') {
  546.       input_stack::get_char();
  547.       c = input_stack::peek_char();
  548.       if (c == 'i') {
  549.     input_stack::get_char();
  550.     c = input_stack::peek_char();
  551.     if (c == 'g') {
  552.       input_stack::get_char();
  553.       c = input_stack::peek_char();
  554.       if (c == 'h') {
  555.         input_stack::get_char();
  556.         c = input_stack::peek_char();
  557.         if (c == 't') {
  558.           input_stack::get_char();
  559.           context_buffer = ".height";
  560.           return DOT_HT;
  561.         }
  562.         input_stack::push_back('h');
  563.       }
  564.       input_stack::push_back('g');
  565.     }
  566.     input_stack::push_back('i');
  567.       }
  568.       input_stack::push_back('e');
  569.     }
  570.     input_stack::push_back('h');
  571.     return '.';
  572.   case 'x':
  573.     input_stack::get_char();
  574.     context_buffer = ".x";
  575.     return DOT_X;
  576.   case 'y':
  577.     input_stack::get_char();
  578.     context_buffer = ".y";
  579.     return DOT_Y;
  580.   case 'c':
  581.     input_stack::get_char();
  582.     c = input_stack::peek_char();
  583.     if (c == 'e') {
  584.       input_stack::get_char();
  585.       c = input_stack::peek_char();
  586.       if (c == 'n') {
  587.     input_stack::get_char();
  588.     c = input_stack::peek_char();
  589.     if (c == 't') {
  590.       input_stack::get_char();
  591.       c = input_stack::peek_char();
  592.       if (c == 'e') {
  593.         input_stack::get_char();
  594.         c = input_stack::peek_char();
  595.         if (c == 'r') {
  596.           input_stack::get_char();
  597.           context_buffer = ".center";
  598.           return DOT_C;
  599.         }
  600.         input_stack::push_back('e');
  601.       }
  602.       input_stack::push_back('t');
  603.     }
  604.     input_stack::push_back('n');
  605.       }
  606.       input_stack::push_back('e');
  607.     }
  608.     context_buffer = ".c";
  609.     return DOT_C;
  610.   case 'n':
  611.     input_stack::get_char();
  612.     c = input_stack::peek_char();
  613.     if (c == 'e') {
  614.       input_stack::get_char();
  615.       context_buffer = ".ne";
  616.       return DOT_NE;
  617.     }
  618.     else if (c == 'w') {
  619.       input_stack::get_char();
  620.       context_buffer = ".nw";
  621.       return DOT_NW;
  622.     }
  623.     else {
  624.       context_buffer = ".n";
  625.       return DOT_N;
  626.     }
  627.     break;
  628.   case 'e':
  629.     input_stack::get_char();
  630.     c = input_stack::peek_char();
  631.     if (c == 'n') {
  632.       input_stack::get_char();
  633.       c = input_stack::peek_char();
  634.       if (c == 'd') {
  635.     input_stack::get_char();
  636.     context_buffer = ".end";
  637.     return DOT_END;
  638.       }
  639.       input_stack::push_back('n');
  640.       context_buffer = ".e";
  641.       return DOT_E;
  642.     }
  643.     context_buffer = ".e";
  644.     return DOT_E;
  645.   case 'w':
  646.     input_stack::get_char();
  647.     c = input_stack::peek_char();
  648.     if (c == 'i') {
  649.       input_stack::get_char();
  650.       c = input_stack::peek_char();
  651.       if (c == 'd') {
  652.     input_stack::get_char();
  653.     c = input_stack::peek_char();
  654.     if (c == 't') {
  655.       input_stack::get_char();
  656.       c = input_stack::peek_char();
  657.       if (c == 'h') {
  658.         input_stack::get_char();
  659.         context_buffer = ".width";
  660.         return DOT_WID;
  661.       }
  662.       input_stack::push_back('t');
  663.     }
  664.     context_buffer = ".wid";
  665.     return DOT_WID;
  666.       }
  667.       input_stack::push_back('i');
  668.     }
  669.     context_buffer = ".w";
  670.     return DOT_W;
  671.   case 's':
  672.     input_stack::get_char();
  673.     c = input_stack::peek_char();
  674.     if (c == 'e') {
  675.       input_stack::get_char();
  676.       context_buffer = ".se";
  677.       return DOT_SE;
  678.     }
  679.     else if (c == 'w') {
  680.       input_stack::get_char();
  681.       context_buffer = ".sw";
  682.       return DOT_SW;
  683.     }
  684.     else {
  685.       if (c == 't') {
  686.     input_stack::get_char();
  687.     c = input_stack::peek_char();
  688.     if (c == 'a') {
  689.       input_stack::get_char();
  690.       c = input_stack::peek_char();
  691.       if (c == 'r') {
  692.         input_stack::get_char();
  693.         c = input_stack::peek_char();
  694.         if (c == 't') {
  695.           input_stack::get_char();
  696.           context_buffer = ".start";
  697.           return DOT_START;
  698.         }
  699.         input_stack::push_back('r');
  700.       }
  701.       input_stack::push_back('a');
  702.     }
  703.     input_stack::push_back('t');
  704.       }
  705.       context_buffer = ".s";
  706.       return DOT_S;
  707.     }
  708.     break;
  709.   case 't':
  710.     input_stack::get_char();
  711.     c = input_stack::peek_char();
  712.     if (c == 'o') {
  713.       input_stack::get_char();
  714.       c = input_stack::peek_char();
  715.       if (c == 'p') {
  716.     input_stack::get_char();
  717.     context_buffer = ".top";
  718.     return DOT_N;
  719.       }
  720.       input_stack::push_back('o');
  721.     }
  722.     context_buffer = ".t";
  723.     return DOT_N;
  724.   case 'l':
  725.     input_stack::get_char();
  726.     c = input_stack::peek_char();
  727.     if (c == 'e') {
  728.       input_stack::get_char();
  729.       c = input_stack::peek_char();
  730.       if (c == 'f') {
  731.     input_stack::get_char();
  732.     c = input_stack::peek_char();
  733.     if (c == 't') {
  734.       input_stack::get_char();
  735.       context_buffer = ".left";
  736.       return DOT_W;
  737.     }
  738.     input_stack::push_back('f');
  739.       }
  740.       input_stack::push_back('e');
  741.     }
  742.     context_buffer = ".l";
  743.     return DOT_W;
  744.   case 'r':
  745.     input_stack::get_char();
  746.     c = input_stack::peek_char();
  747.     if (c == 'a') {
  748.       input_stack::get_char();
  749.       c = input_stack::peek_char();
  750.       if (c == 'd') {
  751.     input_stack::get_char();
  752.     context_buffer = ".rad";
  753.     return DOT_RAD;
  754.       }
  755.       input_stack::push_back('a');
  756.     }
  757.     else if (c == 'i') {
  758.       input_stack::get_char();
  759.       c = input_stack::peek_char();
  760.       if (c == 'g') {
  761.     input_stack::get_char();
  762.     c = input_stack::peek_char();
  763.     if (c == 'h') {
  764.       input_stack::get_char();
  765.       c = input_stack::peek_char();
  766.       if (c == 't') {
  767.         input_stack::get_char();
  768.         context_buffer = ".right";
  769.         return DOT_E;
  770.       }
  771.       input_stack::push_back('h');
  772.     }
  773.     input_stack::push_back('g');
  774.       }
  775.       input_stack::push_back('i');
  776.     }
  777.     context_buffer = ".r";
  778.     return DOT_E;
  779.   case 'b':
  780.     input_stack::get_char();
  781.     c = input_stack::peek_char();
  782.     if (c == 'o') {
  783.       input_stack::get_char();
  784.       c = input_stack::peek_char();
  785.       if (c == 't') {
  786.     input_stack::get_char();
  787.     c = input_stack::peek_char();
  788.     if (c == 't') {
  789.       input_stack::get_char();
  790.       c = input_stack::peek_char();
  791.       if (c == 'o') {
  792.         input_stack::get_char();
  793.         c = input_stack::peek_char();
  794.         if (c == 'm') {
  795.           input_stack::get_char();
  796.           context_buffer = ".bottom";
  797.           return DOT_S;
  798.         }
  799.         input_stack::push_back('o');
  800.       }
  801.       input_stack::push_back('t');
  802.     }
  803.     context_buffer = ".bot";
  804.     return DOT_S;
  805.       }
  806.       input_stack::push_back('o');
  807.     }
  808.     context_buffer = ".b";
  809.     return DOT_S;
  810.   default:
  811.     context_buffer = '.';
  812.     return '.';
  813.   }
  814. }
  815.  
  816. int get_token(int lookup_flag)
  817. {
  818.   context_buffer.clear();
  819.   for (;;) {
  820.     int n = 0;
  821.     int bol = input_stack::bol();
  822.     int c = input_stack::get_char();
  823.     if (bol && c == command_char) {
  824.       token_buffer.clear();
  825.       token_buffer += c;
  826.       // the newline is not part of the token
  827.       for (;;) {
  828.     c = input_stack::peek_char();
  829.     if (c == EOF || c == '\n')
  830.       break;
  831.     input_stack::get_char();
  832.     token_buffer += char(c);
  833.       }
  834.       context_buffer = token_buffer;
  835.       return COMMAND_LINE;
  836.     }
  837.     switch (c) {
  838.     case EOF:
  839.       return EOF;
  840.     case ' ':
  841.     case '\t':
  842.       break;
  843.     case '\\':
  844.       {
  845.     int d = input_stack::peek_char();
  846.     if (d != '\n') {
  847.       context_buffer = '\\';
  848.       return '\\';
  849.     }
  850.     input_stack::get_char();
  851.     break;
  852.       }
  853.     case '#':
  854.       do {
  855.     c = input_stack::get_char();
  856.       } while (c != '\n' && c != EOF);
  857.       if (c == '\n')
  858.     context_buffer = '\n';
  859.       return c;
  860.     case '"':
  861.       context_buffer = '"';
  862.       token_buffer.clear();
  863.       for (;;) {
  864.     c = input_stack::get_char();
  865.     if (c == '\\') {
  866.       context_buffer += '\\';
  867.       c = input_stack::peek_char();
  868.       if (c == '"') {
  869.         input_stack::get_char();
  870.         token_buffer += '"';
  871.         context_buffer += '"';
  872.       }
  873.       else
  874.         token_buffer += '\\';
  875.     }
  876.     else if (c == '\n') {
  877.       error("newline in string");
  878.       break;
  879.     }
  880.     else if (c == EOF) {
  881.       error("missing `\"'");
  882.       break;
  883.     }
  884.     else if (c == '"') {
  885.       context_buffer += '"';
  886.       break;
  887.     }
  888.     else {
  889.       context_buffer += char(c);
  890.       token_buffer += char(c);
  891.     }
  892.       }
  893.       return TEXT;
  894.     case '0':
  895.     case '1':
  896.     case '2':
  897.     case '3':
  898.     case '4':
  899.     case '5':
  900.     case '6':
  901.     case '7':
  902.     case '8':
  903.     case '9':
  904.       {   
  905.     int overflow = 0;
  906.     n = 0;
  907.     for (;;) {
  908.       if (n > (INT_MAX - 9)/10) {
  909.         overflow = 1;
  910.         break;
  911.       }
  912.       n *= 10;
  913.       n += c - '0';
  914.       context_buffer += char(c);
  915.       c = input_stack::peek_char();
  916.       if (c == EOF || !csdigit(c))
  917.         break;
  918.       c = input_stack::get_char();
  919.     }
  920.     token_double = n;
  921.     if (overflow) {
  922.       for (;;) {
  923.         token_double *= 10.0;
  924.         token_double += c - '0';
  925.         context_buffer += char(c);
  926.         c = input_stack::peek_char();
  927.         if (c == EOF || !csdigit(c))
  928.           break;
  929.         c = input_stack::get_char();
  930.       }
  931.       // if somebody asks for 1000000000000th, we will silently
  932.       // give them INT_MAXth
  933.       double temp = token_double; // work around gas 1.34/sparc bug
  934.       if (token_double > INT_MAX)
  935.         n = INT_MAX;
  936.       else
  937.         n = int(temp);
  938.     }
  939.       }
  940.       switch (c) {
  941.       case 'i':
  942.       case 'I':
  943.     context_buffer += char(c);
  944.     input_stack::get_char();
  945.     return NUMBER;
  946.       case '.':
  947.     {
  948.       context_buffer += '.';
  949.       input_stack::get_char();
  950.     got_dot:
  951.       double factor = 1.0;
  952.       for (;;) {
  953.         c = input_stack::peek_char();
  954.         if (!c == EOF || !csdigit(c))
  955.           break;
  956.         input_stack::get_char();
  957.         context_buffer += char(c);
  958.         factor /= 10.0;
  959.         if (c != '0')
  960.           token_double += factor*(c - '0');
  961.       }
  962.       if (c != 'e' && c != 'E') {
  963.         if (c == 'i' || c == 'I') {
  964.           context_buffer += char(c);
  965.           input_stack::get_char();
  966.         }
  967.         return NUMBER;
  968.       }
  969.     }
  970.     // fall through
  971.       case 'e':
  972.       case 'E':
  973.     {
  974.       int echar = c;
  975.       input_stack::get_char();
  976.       c = input_stack::peek_char();
  977.       int sign = '+';
  978.       if (c == '+' || c == '-') {
  979.         sign = c;
  980.         input_stack::get_char();
  981.         c = input_stack::peek_char();
  982.         if (c == EOF || !csdigit(c)) {
  983.           input_stack::push_back(sign);
  984.           input_stack::push_back(echar);
  985.           return NUMBER;
  986.         }
  987.         context_buffer += char(echar);
  988.         context_buffer += char(sign);
  989.       }
  990.       else {
  991.         if (c == EOF || !csdigit(c)) {
  992.           input_stack::push_back(echar);
  993.           return NUMBER;
  994.         }
  995.         context_buffer += char(echar);
  996.       }
  997.       input_stack::get_char();
  998.       context_buffer += char(c);
  999.       n = c - '0';
  1000.       for (;;) {
  1001.         c = input_stack::peek_char();
  1002.         if (c == EOF || !csdigit(c))
  1003.           break;
  1004.         input_stack::get_char();
  1005.         context_buffer += char(c);
  1006.         n = n*10 + (c - '0');
  1007.       }
  1008.       if (sign == '-')
  1009.         n = -n;
  1010.       if (c == 'i' || c == 'I') {
  1011.         context_buffer += char(c);
  1012.         input_stack::get_char();
  1013.       }
  1014.       token_double *= pow(10.0, n);
  1015.       return NUMBER;
  1016.     }
  1017.       case 'n':
  1018.     input_stack::get_char();
  1019.     c = input_stack::peek_char();
  1020.     if (c == 'd') {
  1021.       input_stack::get_char();
  1022.       token_int = n;
  1023.       context_buffer += "nd";
  1024.       return ORDINAL;
  1025.     }
  1026.     input_stack::push_back('n');
  1027.     return NUMBER;
  1028.       case 'r':
  1029.     input_stack::get_char();
  1030.     c = input_stack::peek_char();
  1031.     if (c == 'd') {
  1032.       input_stack::get_char();
  1033.       token_int = n;
  1034.       context_buffer += "rd";
  1035.       return ORDINAL;
  1036.     }
  1037.     input_stack::push_back('r');
  1038.     return NUMBER;
  1039.       case 't':
  1040.     input_stack::get_char();
  1041.     c = input_stack::peek_char();
  1042.     if (c == 'h') {
  1043.       input_stack::get_char();
  1044.       token_int = n;
  1045.       context_buffer += "th";
  1046.       return ORDINAL;
  1047.     }
  1048.     input_stack::push_back('t');
  1049.     return NUMBER;
  1050.       case 's':
  1051.     input_stack::get_char();
  1052.     c = input_stack::peek_char();
  1053.     if (c == 't') {
  1054.       input_stack::get_char();
  1055.       token_int = n;
  1056.       context_buffer += "st";
  1057.       return ORDINAL;
  1058.     }
  1059.     input_stack::push_back('s');
  1060.     return NUMBER;
  1061.       default:
  1062.     return NUMBER;
  1063.       }
  1064.       break;
  1065.     case '\'':
  1066.       {
  1067.     c = input_stack::peek_char();
  1068.     if (c == 't') {
  1069.       input_stack::get_char();
  1070.       c = input_stack::peek_char();
  1071.       if (c == 'h') {
  1072.         input_stack::get_char();
  1073.         context_buffer = "'th";
  1074.         return TH;
  1075.       }
  1076.       else
  1077.         input_stack::push_back('t');
  1078.     }
  1079.     context_buffer = "'";
  1080.     return '\'';
  1081.       }
  1082.     case '.':
  1083.       {
  1084.     c = input_stack::peek_char();
  1085.     if (c != EOF && csdigit(c)) {
  1086.       n = 0;
  1087.       token_double = 0.0;
  1088.       context_buffer = '.';
  1089.       goto got_dot;
  1090.     }
  1091.     return get_token_after_dot(c);
  1092.       }
  1093.     case '<':
  1094.       c = input_stack::peek_char();
  1095.       if (c == '-') {
  1096.     input_stack::get_char();
  1097.     c = input_stack::peek_char();
  1098.     if (c == '>') {
  1099.       input_stack::get_char();
  1100.       context_buffer = "<->";
  1101.       return DOUBLE_ARROW_HEAD;
  1102.     }
  1103.     context_buffer = "<-";
  1104.     return LEFT_ARROW_HEAD;
  1105.       }
  1106.       else if (c == '=') {
  1107.     input_stack::get_char();
  1108.     context_buffer = "<=";
  1109.     return LESSEQUAL;
  1110.       }
  1111.       context_buffer = "<";
  1112.       return '<';
  1113.     case '-':
  1114.       c = input_stack::peek_char();
  1115.       if (c == '>') {
  1116.     input_stack::get_char();
  1117.     context_buffer = "->";
  1118.     return RIGHT_ARROW_HEAD;
  1119.       }
  1120.       context_buffer = "-";
  1121.       return '-';
  1122.     case '!':
  1123.       c = input_stack::peek_char();
  1124.       if (c == '=') {
  1125.     input_stack::get_char();
  1126.     context_buffer = "!=";
  1127.     return NOTEQUAL;
  1128.       }
  1129.       context_buffer = "!";
  1130.       return '!';
  1131.     case '>':
  1132.       c = input_stack::peek_char();
  1133.       if (c == '=') {
  1134.     input_stack::get_char();
  1135.     context_buffer = ">=";
  1136.     return GREATEREQUAL;
  1137.       }
  1138.       context_buffer = ">";
  1139.       return '>';
  1140.     case '=':
  1141.       c = input_stack::peek_char();
  1142.       if (c == '=') {
  1143.     input_stack::get_char();
  1144.     context_buffer = "==";
  1145.     return EQUALEQUAL;
  1146.       }
  1147.       context_buffer = "=";
  1148.       return '=';
  1149.     case '&':
  1150.       c = input_stack::peek_char();
  1151.       if (c == '&') {
  1152.     input_stack::get_char();
  1153.     context_buffer = "&&";
  1154.     return ANDAND;
  1155.       }
  1156.       context_buffer = "&";
  1157.       return '&';
  1158.     case '|':
  1159.       c = input_stack::peek_char();
  1160.       if (c == '|') {
  1161.     input_stack::get_char();
  1162.     context_buffer = "||";
  1163.     return OROR;
  1164.       }
  1165.       context_buffer = "|";
  1166.       return '|';
  1167.     default:
  1168.       if (c != EOF && csalpha(c)) {
  1169.     token_buffer.clear();
  1170.     token_buffer = c;
  1171.     for (;;) {
  1172.       c = input_stack::peek_char();
  1173.       if (c == EOF || (!csalnum(c) && c != '_'))
  1174.         break;
  1175.       input_stack::get_char();
  1176.       token_buffer += char(c);
  1177.     }
  1178.     int tok = lookup_keyword(token_buffer.contents(),
  1179.                  token_buffer.length());
  1180.     if (tok != 0) {
  1181.       context_buffer = token_buffer;
  1182.       return tok;
  1183.     }
  1184.     char *def = 0;
  1185.     if (lookup_flag) {
  1186.       token_buffer += '\0';
  1187.       def = macro_table.lookup(token_buffer.contents());
  1188.       token_buffer.set_length(token_buffer.length() - 1);
  1189.       if (def) {
  1190.         if (c == '(') {
  1191.           input_stack::get_char();
  1192.           interpolate_macro_with_args(def);
  1193.         }
  1194.         else
  1195.           input_stack::push(new macro_input(def));
  1196.       }
  1197.     }
  1198.     if (!def) {
  1199.       context_buffer = token_buffer;
  1200.       if (csupper(token_buffer[0]))
  1201.         return LABEL;
  1202.       else
  1203.         return VARIABLE;
  1204.     }
  1205.       }
  1206.       else {
  1207.     context_buffer = char(c);
  1208.     return (unsigned char)c;
  1209.       }
  1210.       break;
  1211.     }
  1212.   }
  1213. }
  1214.  
  1215. int get_delimited()
  1216. {
  1217.   token_buffer.clear();
  1218.   int c = input_stack::get_char();
  1219.   while (c == ' ' || c == '\t' || c == '\n')
  1220.     c = input_stack::get_char();
  1221.   if (c == EOF) {
  1222.     lex_error("missing delimiter");
  1223.     return 0;
  1224.   }
  1225.   context_buffer = char(c);
  1226.   int had_newline = 0;
  1227.   int start = c;
  1228.   int level = 0;
  1229.   enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
  1230.   for (;;) {
  1231.     c = input_stack::get_char();
  1232.     if (c == EOF) {
  1233.       lex_error("missing closing delimiter");
  1234.       return 0;
  1235.     }
  1236.     if (c == '\n')
  1237.       had_newline = 1;
  1238.     else if (!had_newline)
  1239.       context_buffer += char(c);
  1240.     switch (state) {
  1241.     case NORMAL:
  1242.       if (start == '{') {
  1243.     if (c == '{') {
  1244.       level++;
  1245.       break;
  1246.     }
  1247.     if (c == '}') {
  1248.       if (--level < 0)
  1249.         state = DELIM_END;
  1250.       break;
  1251.     }
  1252.       }
  1253.       else {
  1254.     if (c == start) {
  1255.       state = DELIM_END;
  1256.       break;
  1257.     }
  1258.       }
  1259.       if (c == '"')
  1260.     state = IN_STRING;
  1261.       break;
  1262.     case IN_STRING_QUOTED:
  1263.       if (c == '\n')
  1264.     state = NORMAL;
  1265.       else
  1266.     state = IN_STRING;
  1267.       break;
  1268.     case IN_STRING:
  1269.       if (c == '"' || c == '\n')
  1270.     state = NORMAL;
  1271.       else if (c == '\\')
  1272.     state = IN_STRING_QUOTED;
  1273.       break;
  1274.     case DELIM_END:
  1275.       // This case it just to shut cfront 2.0 up.
  1276.     default:
  1277.       assert(0);
  1278.     }
  1279.     if (state == DELIM_END)
  1280.       break;
  1281.     token_buffer += c;
  1282.   }
  1283.   return 1;
  1284. }
  1285.  
  1286. void do_define()
  1287. {
  1288.   int t = get_token(0);        // do not expand what we are defining
  1289.   if (t != VARIABLE && t != LABEL) {
  1290.     lex_error("can only define variable or placename");
  1291.     return;
  1292.   }
  1293.   token_buffer += '\0';
  1294.   string nm = token_buffer;
  1295.   const char *name = nm.contents();
  1296.   if (!get_delimited())
  1297.     return;
  1298.   token_buffer += '\0';
  1299.   macro_table.define(name, strsave(token_buffer.contents()));
  1300. }
  1301.  
  1302. void do_undef()
  1303. {
  1304.   int t = get_token(0);        // do not expand what we are undefining
  1305.   if (t != VARIABLE && t != LABEL) {
  1306.     lex_error("can only define variable or placename");
  1307.     return;
  1308.   }
  1309.   token_buffer += '\0';
  1310.   macro_table.define(token_buffer.contents(), 0);
  1311. }
  1312.  
  1313.  
  1314. class for_input : public input {
  1315.   char *var;
  1316.   char *body;
  1317.   double to;
  1318.   int by_is_multiplicative;
  1319.   double by;
  1320.   const char *p;
  1321.   int done_newline;
  1322. public:
  1323.   for_input(char *, double, int, double, char *);
  1324.   ~for_input();
  1325.   int get();
  1326.   int peek();
  1327. };
  1328.  
  1329. for_input::for_input(char *vr, double t, int bim, double b, char *bd)
  1330. : var(vr), to(t), by_is_multiplicative(bim), by(b), body(bd), p(body),
  1331.   done_newline(0)
  1332. {
  1333. }
  1334.  
  1335. for_input::~for_input()
  1336. {
  1337.   a_delete var;
  1338.   a_delete body;
  1339. }
  1340.  
  1341. int for_input::get()
  1342. {
  1343.   if (p == 0)
  1344.     return EOF;
  1345.   for (;;) {
  1346.     if (*p != '\0')
  1347.       return (unsigned char)*p++;
  1348.     if (!done_newline) {
  1349.       done_newline = 1;
  1350.       return '\n';
  1351.     }
  1352.     double val;
  1353.     if (!lookup_variable(var, &val)) {
  1354.       lex_error("body of `for' terminated enclosing block");
  1355.       return EOF;
  1356.     }
  1357.     if (by_is_multiplicative)
  1358.       val *= by;
  1359.     else
  1360.       val += by;
  1361.     define_variable(var, val);
  1362.     if (val > to) {
  1363.       p = 0;
  1364.       return EOF;
  1365.     }
  1366.     p = body;
  1367.     done_newline = 0;
  1368.   }
  1369. }
  1370.  
  1371. int for_input::peek()
  1372. {
  1373.   if (p == 0)
  1374.     return EOF;
  1375.   if (*p != '\0')
  1376.     return (unsigned char)*p;
  1377.   if (!done_newline)
  1378.     return '\n';
  1379.   double val;
  1380.   if (!lookup_variable(var, &val))
  1381.     return EOF;
  1382.   if (by_is_multiplicative) {
  1383.     if (val * by > to)
  1384.       return EOF;
  1385.   }
  1386.   else {
  1387.     if (val + by > to)
  1388.       return EOF;
  1389.   }
  1390.   if (*body == '\0')
  1391.     return EOF;
  1392.   return (unsigned char)*body;
  1393. }
  1394.  
  1395. void do_for(char *var, double from, double to, int by_is_multiplicative,
  1396.         double by, char *body)
  1397. {
  1398.   define_variable(var, from);
  1399.   if (from <= to)
  1400.     input_stack::push(new for_input(var, to, by_is_multiplicative, by, body));
  1401. }
  1402.  
  1403.  
  1404. void do_copy(const char *filename)
  1405. {
  1406.   errno = 0;
  1407.   FILE *fp = fopen(filename, "r");
  1408.   if (fp == 0) {
  1409.     lex_error("can't open `%1': %2", filename, strerror(errno));
  1410.     return;
  1411.   }
  1412.   input_stack::push(new file_input(fp, filename));
  1413. }
  1414.  
  1415. class copy_thru_input : public input {
  1416.   int done;
  1417.   char *body;
  1418.   char *until;
  1419.   const char *p;
  1420.   const char *ap;
  1421.   int argv[9];
  1422.   int argc;
  1423.   string line;
  1424.   int get_line();
  1425.   virtual int inget() = 0;
  1426. public:
  1427.   copy_thru_input(const char *b, const char *u);
  1428.   ~copy_thru_input();
  1429.   int get();
  1430.   int peek();
  1431. };
  1432.  
  1433. class copy_file_thru_input : public copy_thru_input {
  1434.   input *in;
  1435. public:
  1436.   copy_file_thru_input(input *, const char *b, const char *u);
  1437.   ~copy_file_thru_input();
  1438.   int inget();
  1439. };
  1440.  
  1441. copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
  1442.                        const char *u)
  1443. : in(i), copy_thru_input(b, u)
  1444. {
  1445. }
  1446.  
  1447. copy_file_thru_input::~copy_file_thru_input()
  1448. {
  1449.   delete in;
  1450. }
  1451.  
  1452. int copy_file_thru_input::inget()
  1453. {
  1454.   if (!in)
  1455.     return EOF;
  1456.   else
  1457.     return in->get();
  1458. }
  1459.  
  1460. class copy_rest_thru_input : public copy_thru_input {
  1461. public:
  1462.   copy_rest_thru_input(const char *, const char *u);
  1463.   int inget();
  1464. };
  1465.  
  1466. copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
  1467. : copy_thru_input(b, u)
  1468. {
  1469. }
  1470.  
  1471. int copy_rest_thru_input::inget()
  1472. {
  1473.   while (next != 0) {
  1474.     int c = next->get();
  1475.     if (c != EOF)
  1476.       return c;
  1477.     if (next->next == 0)
  1478.       return EOF;
  1479.     input *tem = next;
  1480.     next = next->next;
  1481.     delete tem;
  1482.   }
  1483.   return EOF;
  1484.  
  1485. }
  1486.  
  1487. copy_thru_input::copy_thru_input(const char *b, const char *u)
  1488. : done(0)
  1489. {
  1490.   ap = 0;
  1491.   body = process_body(b);
  1492.   p = 0;
  1493.   until = strsave(u);
  1494. }
  1495.  
  1496.  
  1497. copy_thru_input::~copy_thru_input()
  1498. {
  1499.   a_delete body;
  1500.   a_delete until;
  1501. }
  1502.  
  1503. int copy_thru_input::get()
  1504. {
  1505.   if (ap) {
  1506.     if (*ap != '\0')
  1507.       return (unsigned char)*ap++;
  1508.     ap = 0;
  1509.   }
  1510.   for (;;) {
  1511.     if (p == 0) {
  1512.       if (!get_line())
  1513.     break;
  1514.       p = body;
  1515.     }
  1516.     if (*p == '\0') {
  1517.       p = 0;
  1518.       return '\n';
  1519.     }
  1520.     while (*p >= ARG1 && *p <= ARG1 + 8) {
  1521.       int i = *p++ - ARG1;
  1522.       if (i < argc && line[argv[i]] != '\0') {
  1523.     ap = line.contents() + argv[i];
  1524.     return (unsigned char)*ap++;
  1525.       }
  1526.     }
  1527.     if (*p != '\0')
  1528.       return (unsigned char)*p++;
  1529.   }
  1530.   return EOF;
  1531. }
  1532.  
  1533. int copy_thru_input::peek()
  1534. {
  1535.   if (ap) {
  1536.     if (*ap != '\0')
  1537.       return (unsigned char)*ap;
  1538.     ap = 0;
  1539.   }
  1540.   for (;;) {
  1541.     if (p == 0) {
  1542.       if (!get_line())
  1543.     break;
  1544.       p = body;
  1545.     }
  1546.     if (*p == '\0')
  1547.       return '\n';
  1548.     while (*p >= ARG1 && *p <= ARG1 + 8) {
  1549.       int i = *p++ - ARG1;
  1550.       if (i < argc && line[argv[i]] != '\0') {
  1551.     ap = line.contents() + argv[i];
  1552.     return (unsigned char)*ap;
  1553.       }
  1554.     }
  1555.     if (*p != '\0')
  1556.       return (unsigned char)*p;
  1557.   }
  1558.   return EOF;
  1559. }
  1560.  
  1561. int copy_thru_input::get_line()
  1562. {
  1563.   if (done)
  1564.     return 0;
  1565.   line.clear();
  1566.   argc = 0;
  1567.   int c = inget();
  1568.   for (;;) {
  1569.     while (c == ' ')
  1570.       c = inget();
  1571.     if (c == EOF || c == '\n')
  1572.       break;
  1573.     if (argc == 9) {
  1574.       do {
  1575.     c = inget();
  1576.       } while (c != '\n' && c != EOF);
  1577.       break;
  1578.     }
  1579.     argv[argc++] = line.length();
  1580.     do {
  1581.       line += char(c);
  1582.       c = inget();
  1583.     } while (c != ' ' && c != '\n');
  1584.     line += '\0';
  1585.   }
  1586.   if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
  1587.     done = 1;
  1588.     return 0;
  1589.   }
  1590.   return argc > 0 || c == '\n';
  1591. }
  1592.  
  1593. class simple_file_input : public input {
  1594.   const char *filename;
  1595.   int lineno;
  1596.   FILE *fp;
  1597. public:
  1598.   simple_file_input(FILE *, const char *);
  1599.   ~simple_file_input();
  1600.   int get();
  1601.   int peek();
  1602.   int get_location(const char **, int *);
  1603. };
  1604.  
  1605. simple_file_input::simple_file_input(FILE *p, const char *s)
  1606. : filename(s), fp(p), lineno(1)
  1607. {
  1608. }
  1609.  
  1610. simple_file_input::~simple_file_input()
  1611. {
  1612.   // don't delete the filename
  1613.   fclose(fp);
  1614. }
  1615.  
  1616. int simple_file_input::get()
  1617. {
  1618.   int c = getc(fp);
  1619.   while (illegal_input_char(c)) {
  1620.     error("illegal input character code %1", c);
  1621.     c = getc(fp);
  1622.   }
  1623.   if (c == '\n')
  1624.     lineno++;
  1625.   return c;
  1626. }
  1627.  
  1628. int simple_file_input::peek()
  1629. {
  1630.   int c = getc(fp);
  1631.   while (illegal_input_char(c)) {
  1632.     error("illegal input character code %1", c);
  1633.     c = getc(fp);
  1634.   }
  1635.   if (c != EOF)
  1636.     ungetc(c, fp);
  1637.   return c;
  1638. }
  1639.  
  1640. int simple_file_input::get_location(const char **fnp, int *lnp)
  1641. {
  1642.   *fnp = filename;
  1643.   *lnp = lineno;
  1644.   return 1;
  1645. }
  1646.  
  1647.  
  1648. void copy_file_thru(const char *filename, const char *body, const char *until)
  1649. {
  1650.   errno = 0;
  1651.   FILE *fp = fopen(filename, "r");
  1652.   if (fp == 0) {
  1653.     lex_error("can't open `%1': %2", filename, strerror(errno));
  1654.     return;
  1655.   }
  1656.   input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
  1657.                        body, until);
  1658.   input_stack::push(in);
  1659. }
  1660.  
  1661. void copy_rest_thru(const char *body, const char *until)
  1662. {
  1663.   input_stack::push(new copy_rest_thru_input(body, until));
  1664. }
  1665.  
  1666. void push_body(const char *s)
  1667. {
  1668.   input_stack::push(new char_input('\n'));
  1669.   input_stack::push(new macro_input(s));
  1670. }
  1671.  
  1672. int delim_flag = 0;
  1673.  
  1674. char *get_thru_arg()
  1675. {
  1676.   int c = input_stack::peek_char();
  1677.   while (c == ' ') {
  1678.     input_stack::get_char();
  1679.     c = input_stack::peek_char();
  1680.   }
  1681.   if (c != EOF && csalpha(c)) {
  1682.     // looks like a macro
  1683.     input_stack::get_char();
  1684.     token_buffer = c;
  1685.     for (;;) {
  1686.       c = input_stack::peek_char();
  1687.       if (c == EOF || (!csalnum(c) && c != '_'))
  1688.     break;
  1689.       input_stack::get_char();
  1690.       token_buffer += char(c);
  1691.     }
  1692.     context_buffer = token_buffer;
  1693.     token_buffer += '\0';
  1694.     char *def = macro_table.lookup(token_buffer.contents());
  1695.     if (def)
  1696.       return strsave(def);
  1697.     // I guess it wasn't a macro after all; so push the macro name back.
  1698.     // -2 because we added a '\0'
  1699.     for (int i = token_buffer.length() - 2; i >= 0; i--)
  1700.       input_stack::push_back(token_buffer[i]);
  1701.   }
  1702.   if (get_delimited()) {
  1703.     token_buffer += '\0';
  1704.     return strsave(token_buffer.contents());
  1705.   }
  1706.   else
  1707.     return 0;
  1708. }
  1709.  
  1710. int lookahead_token = -1;
  1711. string old_context_buffer;
  1712.  
  1713. void do_lookahead()
  1714. {
  1715.   if (lookahead_token == -1) {
  1716.     old_context_buffer = context_buffer;
  1717.     lookahead_token = get_token(1);
  1718.   }
  1719. }
  1720.  
  1721. int yylex()
  1722. {
  1723.   if (delim_flag) {
  1724.     assert(lookahead_token == -1);
  1725.     if (delim_flag == 2) {
  1726.       if ((yylval.str = get_thru_arg()) != 0)
  1727.     return DELIMITED;
  1728.       else
  1729.     return 0;
  1730.     }
  1731.     else {
  1732.       if (get_delimited()) {
  1733.     token_buffer += '\0';
  1734.     yylval.str = strsave(token_buffer.contents());
  1735.     return DELIMITED;
  1736.       }
  1737.       else
  1738.     return 0;
  1739.     }
  1740.   }
  1741.   for (;;) {
  1742.     int t;
  1743.     if (lookahead_token >= 0) {
  1744.       t = lookahead_token;
  1745.       lookahead_token = -1;
  1746.     }
  1747.     else
  1748.       t = get_token(1);
  1749.     switch (t) {
  1750.     case '\n':
  1751.       return ';';
  1752.     case EOF:
  1753.       return 0;
  1754.     case DEFINE:
  1755.       do_define();
  1756.       break;
  1757.     case UNDEF:
  1758.       do_undef();
  1759.       break;
  1760.     case ORDINAL:
  1761.       yylval.n = token_int;
  1762.       return t;
  1763.     case NUMBER:
  1764.       yylval.x = token_double;
  1765.       return t;
  1766.     case COMMAND_LINE:
  1767.     case TEXT:
  1768.       token_buffer += '\0';
  1769.       if (!input_stack::get_location(&yylval.lstr.filename,
  1770.                      &yylval.lstr.lineno)) {
  1771.     yylval.lstr.filename = 0;
  1772.     yylval.lstr.lineno = -1;
  1773.       }
  1774.       yylval.lstr.str = strsave(token_buffer.contents());
  1775.       return t;
  1776.     case LABEL:
  1777.     case VARIABLE:
  1778.       token_buffer += '\0';
  1779.       yylval.str = strsave(token_buffer.contents());
  1780.       return t;
  1781.     case LEFT:
  1782.       // change LEFT to LEFT_CORNER when followed by OF
  1783.       old_context_buffer = context_buffer;
  1784.       lookahead_token = get_token(1);
  1785.       if (lookahead_token == OF)
  1786.     return LEFT_CORNER;
  1787.       else
  1788.     return t;
  1789.     case RIGHT:
  1790.       // change RIGHT to RIGHT_CORNER when followed by OF
  1791.       old_context_buffer = context_buffer;
  1792.       lookahead_token = get_token(1);
  1793.       if (lookahead_token == OF)
  1794.     return RIGHT_CORNER;
  1795.       else
  1796.     return t;
  1797.     case UPPER:
  1798.       // recognise UPPER only before LEFT or RIGHT
  1799.       old_context_buffer = context_buffer;
  1800.       lookahead_token = get_token(1);
  1801.       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1802.     yylval.str = strsave("upper");
  1803.     return VARIABLE;
  1804.       }
  1805.       else
  1806.     return t;
  1807.     case LOWER:
  1808.       // recognise LOWER only before LEFT or RIGHT
  1809.       old_context_buffer = context_buffer;
  1810.       lookahead_token = get_token(1);
  1811.       if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1812.     yylval.str = strsave("lower");
  1813.     return VARIABLE;
  1814.       }
  1815.       else
  1816.     return t;
  1817.     case TOP:
  1818.       // recognise TOP only before OF
  1819.       old_context_buffer = context_buffer;
  1820.       lookahead_token = get_token(1);
  1821.       if (lookahead_token != OF) {
  1822.     yylval.str = strsave("top");
  1823.     return VARIABLE;
  1824.       }
  1825.       else
  1826.     return t;
  1827.     case BOTTOM:
  1828.       // recognise BOTTOM only before OF
  1829.       old_context_buffer = context_buffer;
  1830.       lookahead_token = get_token(1);
  1831.       if (lookahead_token != OF) {
  1832.     yylval.str = strsave("bottom");
  1833.     return VARIABLE;
  1834.       }
  1835.       else
  1836.     return t;
  1837.     case CENTER:
  1838.       // recognise CENTER only before OF
  1839.       old_context_buffer = context_buffer;
  1840.       lookahead_token = get_token(1);
  1841.       if (lookahead_token != OF) {
  1842.     yylval.str = strsave("center");
  1843.     return VARIABLE;
  1844.       }
  1845.       else
  1846.     return t;
  1847.     case START:
  1848.       // recognise START only before OF
  1849.       old_context_buffer = context_buffer;
  1850.       lookahead_token = get_token(1);
  1851.       if (lookahead_token != OF) {
  1852.     yylval.str = strsave("start");
  1853.     return VARIABLE;
  1854.       }
  1855.       else
  1856.     return t;
  1857.     case END:
  1858.       // recognise END only before OF
  1859.       old_context_buffer = context_buffer;
  1860.       lookahead_token = get_token(1);
  1861.       if (lookahead_token != OF) {
  1862.     yylval.str = strsave("end");
  1863.     return VARIABLE;
  1864.       }
  1865.       else
  1866.     return t;
  1867.     default:
  1868.       return t;
  1869.     }
  1870.   }
  1871. }
  1872.  
  1873. void lex_error(const char *message,
  1874.            const errarg &arg1,
  1875.            const errarg &arg2,
  1876.            const errarg &arg3)
  1877. {
  1878.   const char *filename;
  1879.   int lineno;
  1880.   if (!input_stack::get_location(&filename, &lineno))
  1881.     error(message, arg1, arg2, arg3);
  1882.   else
  1883.     error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1884. }
  1885.  
  1886. void lex_warning(const char *message,
  1887.          const errarg &arg1,
  1888.          const errarg &arg2,
  1889.          const errarg &arg3)
  1890. {
  1891.   const char *filename;
  1892.   int lineno;
  1893.   if (!input_stack::get_location(&filename, &lineno))
  1894.     warning(message, arg1, arg2, arg3);
  1895.   else
  1896.     warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1897. }
  1898.  
  1899. void yyerror(const char *s)
  1900. {
  1901.   const char *filename;
  1902.   int lineno;
  1903.   const char *context = 0;
  1904.   if (lookahead_token == -1) {
  1905.     if (context_buffer.length() > 0) {
  1906.       context_buffer += '\0';
  1907.       context = context_buffer.contents();
  1908.     }
  1909.   }
  1910.   else {
  1911.     if (old_context_buffer.length() > 0) {
  1912.       old_context_buffer += '\0';
  1913.       context = old_context_buffer.contents();
  1914.     }
  1915.   }
  1916.   if (!input_stack::get_location(&filename, &lineno)) {
  1917.     if (context) {
  1918.       if (context[0] == '\n' && context[1] == '\0')
  1919.     error("%1 before newline", s);
  1920.       else
  1921.     error("%1 before `%2'", s, context);
  1922.     }
  1923.     else
  1924.       error("%1 at end of picture", s);
  1925.   }
  1926.   else {
  1927.     if (context) {
  1928.       if (context[0] == '\n' && context[1] == '\0')
  1929.     error_with_file_and_line(filename, lineno, "%1 before newline", s);
  1930.       else
  1931.     error_with_file_and_line(filename, lineno, "%1 before `%2'",
  1932.                  s, context);
  1933.     }
  1934.     else
  1935.       error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
  1936.   }
  1937. }
  1938.  
  1939.